#ifndef _RCC_HW_H_
#define _RCC_HW_H_

#include "soc.h"

typedef struct {
	_RW CR;            /*!< RCC clock control register,                                  offset: 0x00 */
	_RW PLLCFGR;       /*!< RCC PLL configuration register,                              offset: 0x04 */
	_RW CFGR;          /*!< RCC clock configuration register,                            offset: 0x08 */
	_RW CIR;           /*!< RCC clock interrupt register,                                offset: 0x0C */
	_RW AHB1RSTR;      /*!< RCC AHB1 peripheral reset register,                          offset: 0x10 */
	_RW AHB2RSTR;      /*!< RCC AHB2 peripheral reset register,                          offset: 0x14 */
	_RW AHB3RSTR;      /*!< RCC AHB3 peripheral reset register,                          offset: 0x18 */
	_NU RESERVED0;     /*!< Reserved, 0x1C                                                            */
	_RW APB1RSTR;      /*!< RCC APB1 peripheral reset register,                          offset: 0x20 */
	_RW APB2RSTR;      /*!< RCC APB2 peripheral reset register,                          offset: 0x24 */
	_NU RESERVED1[2];  /*!< Reserved, 0x28-0x2C                                                       */
	_RW AHB1ENR;       /*!< RCC AHB1 peripheral clock register,                          offset: 0x30 */
	_RW AHB2ENR;       /*!< RCC AHB2 peripheral clock register,                          offset: 0x34 */
	_RW AHB3ENR;       /*!< RCC AHB3 peripheral clock register,                          offset: 0x38 */
	_NU RESERVED2;     /*!< Reserved, 0x3C                                                            */
	_RW APB1ENR;       /*!< RCC APB1 peripheral clock enable register,                   offset: 0x40 */
	_RW APB2ENR;       /*!< RCC APB2 peripheral clock enable register,                   offset: 0x44 */
	_NU RESERVED3[2];  /*!< Reserved, 0x48-0x4C                                                       */
	_RW AHB1LPENR;     /*!< RCC AHB1 peripheral clock enable in low power mode register, offset: 0x50 */
	_RW AHB2LPENR;     /*!< RCC AHB2 peripheral clock enable in low power mode register, offset: 0x54 */
	_RW AHB3LPENR;     /*!< RCC AHB3 peripheral clock enable in low power mode register, offset: 0x58 */
	_NU RESERVED4;     /*!< Reserved, 0x5C                                                            */
	_RW APB1LPENR;     /*!< RCC APB1 peripheral clock enable in low power mode register, offset: 0x60 */
	_RW APB2LPENR;     /*!< RCC APB2 peripheral clock enable in low power mode register, offset: 0x64 */
	_NU RESERVED5[2];  /*!< Reserved, 0x68-0x6C                                                       */
	_RW BDCR;          /*!< RCC Backup domain control register,                          offset: 0x70 */
	_RW CSR;           /*!< RCC clock control & status register,                         offset: 0x74 */
	_NU RESERVED6[2];  /*!< Reserved, 0x78-0x7C                                                       */
	_RW SSCGR;         /*!< RCC spread spectrum clock generation register,               offset: 0x80 */
	_RW PLLI2SCFGR;    /*!< RCC PLLI2S configuration register,                           offset: 0x84 */
} RCC_Struct;

extern RCC_Struct SOC_RCC;

/**
 * 时钟控制寄存器
 */
#define RCC_CR_HSION               (0x1U<<0)               /* 内部高速时钟使能 */
#define RCC_CR_HSITRIM_0_1FH(val)  (((val) & 0x1FU) << 3)  /* 微调校准值 */
#define RCC_CR_HSEON               (0x1U<<16)              /* HSE时钟使能 */
#define RCC_CR_HSEBYP              (0x1U<<18)              /* 使用有源晶振 */
#define RCC_CR_CSSON               (0x1U<<19)              /* 时钟安全系统使能，HSE故障时硬件清零 */
#define RCC_CR_PLLON               (0x1U<<24)              /* 主PLL使能 */
#define RCC_CR_PLLI2SON            (0x1U<<26)              /* PLLI2S使能 */
#define _RCC_IsHsiReady(dev)       ((dev).CR & (0x1U<<1))
#define _RCC_IsHseReady(dev)       ((dev).CR & (0x1U<<17))
#define _RCC_IsPllReady(dev)       ((dev).CR & (0x1U<<25))
#define _RCC_IsPllI2sReady(dev)    ((dev).CR & (0x1U<<27))

/**
 * PLL配置
 */
#define RCC_PLLCFGR_PLLM_2_63D(val)     (((val) & 0x3F) << 0)  /* VCO输入分频，确保VCO的输入在1~2MHz之间，推荐2MHz */
#define RCC_PLLCFGR_PLLN_50_432D(val)   (((val) & 0x1FF) << 6) /* VCO的倍频系数，确保VCO的输出在192~432之间，手册中说PLLN应大于192，CubeMax中PLLN大于50即可 */
#define RCC_PLLCFGR_PLLP_DIV2           (0x0U<<16)             /* PLL系统时钟分频系数，2分频 */
#define RCC_PLLCFGR_PLLP_DIV4           (0x1U<<16)
#define RCC_PLLCFGR_PLLP_DIV6           (0x2U<<16)
#define RCC_PLLCFGR_PLLP_DIV8           (0x3U<<16)
#define RCC_PLLCFGR_PLLSRC_HSI          (0x0U<<22)             /* 使用HSI作为输入时钟源 */
#define RCC_PLLCFGR_PLLSRC_HSE          (0x1U<<22)
#define RCC_PLLCFGR_PLLQ_2_15D(val)     (((val) & 0xF) << 24)  /* USB_OTG_FS/SDIO/RNG时钟分频系数，USB需要48MHz，SDIO/RNG不能大于48MHz，这个是从VCO上进行分频的 */

/**
 * 时钟配置
 */
#define RCC_CFGR_SW_HSI                 (0x0U<<0)  /* 使用HSI作为系统时钟 */
#define RCC_CFGR_SW_HSE                 (0x1U<<0)
#define RCC_CFGR_SW_PLL                 (0x2U<<0)
#define RCC_CFGR_HPRE_DIV1              (0x7U<<4)  /* AHB的分频系数，最大168M，使用MAC时，AHB需要大于25MHz */
#define RCC_CFGR_HPRE_DIV2              (0x8U<<4)
#define RCC_CFGR_HPRE_DIV4              (0x9U<<4)
#define RCC_CFGR_HPRE_DIV8              (0xAU<<4)
#define RCC_CFGR_HPRE_DIV16             (0xBU<<4)
#define RCC_CFGR_HPRE_DIV64             (0xCU<<4)
#define RCC_CFGR_HPRE_DIV128            (0xDU<<4)
#define RCC_CFGR_HPRE_DIV256            (0xEU<<4)
#define RCC_CFGR_HPRE_DIV512            (0xFU<<4)
#define RCC_CFGR_PPRE1_DIV1             (0x3U<<10)  /* 低速外设APB1分频系数，最大42M */
#define RCC_CFGR_PPRE1_DIV2             (0x4U<<10)
#define RCC_CFGR_PPRE1_DIV4             (0x5U<<10)
#define RCC_CFGR_PPRE1_DIV8             (0x6U<<10)
#define RCC_CFGR_PPRE1_DIV16            (0x7U<<10)
#define RCC_CFGR_PPRE2_DIV1             (0x3U<<13)  /* 高速外设APB2分频系数，最大84M */
#define RCC_CFGR_PPRE2_DIV2             (0x4U<<13)
#define RCC_CFGR_PPRE2_DIV4             (0x5U<<13)
#define RCC_CFGR_PPRE2_DIV8             (0x6U<<13)
#define RCC_CFGR_PPRE2_DIV16            (0x7U<<13)
#define RCC_CFGR_RTCPRE_2_31D(val)      (((val) & 0x1F) << 16) /* 使用HSE给RTC提供时钟，确保RTC输入时钟为1MHz */
#define RCC_CFGR_MCO1_HSI               (0x0U<<21)  /* MCO1输出HSI时钟 */
#define RCC_CFGR_MCO1_LSE               (0x1U<<21)
#define RCC_CFGR_MCO1_HSE               (0x2U<<21)
#define RCC_CFGR_MCO1_PLL               (0x3U<<21)
#define RCC_CFGR_I2SSRC_PLLI2S          (0x0U<<23)  /* 使用PLLI2S时钟作为I2S时钟源 */
#define RCC_CFGR_I2SSRC_CKIN            (0x1U<<23)  /* 使用I2S_CKIN引脚作为时钟源 */
#define RCC_CFGR_MCO1PRE_DIV1           (0x3U<<24)  /* MCO1输出时钟分频系数 */
#define RCC_CFGR_MCO1PRE_DIV2           (0x4U<<24)
#define RCC_CFGR_MCO1PRE_DIV3           (0x5U<<24)
#define RCC_CFGR_MCO1PRE_DIV4           (0x6U<<24)
#define RCC_CFGR_MCO1PRE_DIV5           (0x7U<<24)
#define RCC_CFGR_MCO2PRE_DIV1           (0x3U<<27)  /* MCO2输出时钟分频系数 */
#define RCC_CFGR_MCO2PRE_DIV2           (0x4U<<27)
#define RCC_CFGR_MCO2PRE_DIV3           (0x5U<<27)
#define RCC_CFGR_MCO2PRE_DIV4           (0x6U<<27)
#define RCC_CFGR_MCO2PRE_DIV5           (0x7U<<27)
#define RCC_CFGR_MCO2_SYSCLK            (0x0U<<30)  /* MCO2输出AHB分频前的时钟 */
#define RCC_CFGR_MCO2_PLLI2S            (0x1U<<30)
#define RCC_CFGR_MCO2_HSE               (0x2U<<30)
#define RCC_CFGR_MCO2_PLL               (0x3U<<30)

/**
 * 时钟中断
 */
/* 只读中断标志 */
#define RCC_CIR_LSIRDYF                 (0x1U<<0)  /* LSI就绪中断标志 */
#define RCC_CIR_LSERDYF                 (0x1U<<1)  /* LSE就绪中断标志 */
#define RCC_CIR_HSIRDYF                 (0x1U<<2)  /* HSI就绪中断标志 */
#define RCC_CIR_HSERDYF                 (0x1U<<3)  /* HSE就绪中断标志 */
#define RCC_CIR_PLLRDYF                 (0x1U<<4)  /* PLL就绪中断标志 */
#define RCC_CIR_PLLI2SRDYF              (0x1U<<5)  /* PLLI2S就绪标志 */
#define RCC_CIR_CSSF                    (0x1U<<6)  /* 时钟安全系统标志 */
/* 中断使能 */
#define RCC_CIR_LSIRDYIE                (0x1U<<8)  /* LSI 就绪中断使能 */
#define RCC_CIR_LSERDYIE                (0x1U<<9)
#define RCC_CIR_HSIRDYIE                (0x1U<<10)
#define RCC_CIR_HSERDYIE                (0x1U<<11)
#define RCC_CIR_PLLRDYIE                (0x1U<<12)
#define RCC_CIR_PLLI2SRDYIE             (0x1U<<13)
/* 写1清除中断标志 */
#define RCC_CIR_LSIRDYC                 (0x1U<<16)  /* 清除LSI中断标志 */
#define RCC_CIR_LSERDYC                 (0x1U<<17)
#define RCC_CIR_HSIRDYC                 (0x1U<<18)
#define RCC_CIR_HSERDYC                 (0x1U<<19)
#define RCC_CIR_PLLRDYC                 (0x1U<<20)
#define RCC_CIR_PLLI2SRDYC              (0x1U<<21)
#define RCC_CIR_CSSC                    (0x1U<<23)  /* 清除时钟安全系统标志 */

#endif /* _RCC_HW_H_ */
